/*
 * QE3e Qt Quick 3D Engine.
 * Copyright (C) 2010 Joris Vaillant and Mathieu Pujol 
 * <joris.vaillant@gmail.com>  <mathieu.pujol87@gmail.com>
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */


#include "Transform.h"

namespace qe3e
{
  Transform::Transform():
      mMatrix()
  {
  }

  void Transform::scale(qreal sX, qreal sY, qreal sZ)
  {
    if(!sX || !sY || !sZ)
    {
      qWarning()<<"Scale by zero is forbiden";
    }
    else
    {
      mMatrix.scale(sX,sY,sZ);
    }
  }

  void Transform::scale(qreal sFactor)
  {
    scale(sFactor,sFactor,sFactor);
  }

  void Transform::scale(const QVector3D &s)
  {
    scale(s.x(),s.y(),s.z());
  }

  Transform Transform::scaled(qreal sX, qreal sY, qreal sZ) const
  {
    Transform ret(*this);
    if(!sX || !sY || !sZ)
    {
      qWarning()<<"Scale by zero is forbiden";
      return ret;
    }
    else
    {
      ret.mMatrix.scale(sX,sY,sZ);
      return ret;
    }
  }

  Transform Transform::scaled(qreal sFactor) const
  {
    return scaled(sFactor, sFactor, sFactor);
  }

  Transform Transform::scaled(const QVector3D& s) const
  {
    return scaled(s.x(), s.y(), s.z());
  }

  /**  @brief remplace la partie translation du transform
    */
  void Transform::setTranslation(qreal tX, qreal tY, qreal tZ)
  {
    mMatrix.setColumn(3,QVector4D(tX,tY,tZ,0.));
  }

  void Transform::setTranslation(const QVector3D & t)
  {
    mMatrix.setColumn(3,QVector4D(t.x(),t.y(),t.z(),0.));
  }

  void Transform::translate(qreal tX, qreal tY, qreal tZ)
  {
    mMatrix.translate(tX,tY,tZ);
  }

  void Transform::translate(const QVector3D &t)
  {
    mMatrix.translate(t);
  }

  Transform Transform::translated(qreal tX, qreal tY, qreal tZ) const
  {
    Transform ret(*this);
    ret.mMatrix.translate(tX, tY, tZ);
    return ret;
  }

  Transform Transform::translated(const QVector3D& t) const
  {
    Transform ret(*this);
    ret.mMatrix.translate(t);
    return ret;
  }

  void Transform::rotate(qreal angle, qreal axisX, qreal axisY, qreal axisZ)
  {
    mMatrix.rotate(angle,axisX,axisY,axisZ);
  }

  void Transform::rotate(qreal angle, const QVector3D &axis)
  {
    mMatrix.rotate(angle,axis);
  }

  void Transform::rotate(const QQuaternion &quat)
  {
    mMatrix.rotate(quat);
  }

  Transform Transform::rotated(qreal angle
                               , qreal axisX
                               , qreal axisY
                               , qreal axisZ) const
  {
    Transform ret(*this);
    ret.mMatrix.rotate(angle, axisX, axisY, axisZ);
    return ret;
  }

  Transform Transform::rotated(qreal angle, const QVector3D& axis) const
  {
    Transform ret(*this);
    ret.mMatrix.rotate(angle, axis);
    return ret;
  }

  Transform Transform::rotated(const QQuaternion& quat) const
  {
    Transform ret(*this);
    ret.mMatrix.rotate(quat);
    return ret;
  }

  void Transform::setIdentity()
  {
    mMatrix.setToIdentity();
  }

  const QMatrix4x4 & Transform::getMatrix() const
  {
    return mMatrix;
  }

  void Transform::getFloatRowMajorMatrix(float * buffer) const
  {
    //collumn 0
    buffer[0]=static_cast<float>(mMatrix.data()[0]);
    buffer[1]=static_cast<float>(mMatrix.data()[4]);
    buffer[2]=static_cast<float>(mMatrix.data()[8]);
    buffer[3]=static_cast<float>(mMatrix.data()[12]);
    //collumn 1
    buffer[4]=static_cast<float>(mMatrix.data()[1]);
    buffer[5]=static_cast<float>(mMatrix.data()[5]);
    buffer[6]=static_cast<float>(mMatrix.data()[9]);
    buffer[7]=static_cast<float>(mMatrix.data()[13]);
    //collumn 2
    buffer[8]=static_cast<float>(mMatrix.data()[2]);
    buffer[9]=static_cast<float>(mMatrix.data()[6]);
    buffer[10]=static_cast<float>(mMatrix.data()[10]);
    buffer[11]=static_cast<float>(mMatrix.data()[14]);
    //collumn 3
    buffer[12]=static_cast<float>(mMatrix.data()[3]);
    buffer[13]=static_cast<float>(mMatrix.data()[7]);
    buffer[14]=static_cast<float>(mMatrix.data()[11]);
    buffer[15]=static_cast<float>(mMatrix.data()[15]);

  }

  void Transform::getFloatColumnMajorMatrix(float * buffer) const
  {
    //collumn 0
    buffer[0]=static_cast<float>(mMatrix.data()[0]);
    buffer[1]=static_cast<float>(mMatrix.data()[1]);
    buffer[2]=static_cast<float>(mMatrix.data()[2]);
    buffer[3]=static_cast<float>(mMatrix.data()[3]);
    //collumn 1
    buffer[4]=static_cast<float>(mMatrix.data()[4]);
    buffer[5]=static_cast<float>(mMatrix.data()[5]);
    buffer[6]=static_cast<float>(mMatrix.data()[6]);
    buffer[7]=static_cast<float>(mMatrix.data()[7]);
    //collumn 2
    buffer[8]=static_cast<float>(mMatrix.data()[8]);
    buffer[9]=static_cast<float>(mMatrix.data()[9]);
    buffer[10]=static_cast<float>(mMatrix.data()[10]);
    buffer[11]=static_cast<float>(mMatrix.data()[11]);
    //collumn 3
    buffer[12]=static_cast<float>(mMatrix.data()[12]);
    buffer[13]=static_cast<float>(mMatrix.data()[13]);
    buffer[14]=static_cast<float>(mMatrix.data()[14]);
    buffer[15]=static_cast<float>(mMatrix.data()[15]);

  }

  Transform Transform::operator*(const Transform & transform) const
  {
    Transform result;
    result.mMatrix = mMatrix*transform.mMatrix;
    return result;
  }

}
